package com.sojson.udp.config;

import java.util.concurrent.CompletableFuture;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.sojson.udp.config.handler.UdpHandlerControl;
import com.sojson.udp.config.handler.UdpHandlerHeartbeat;
import com.sojson.udp.util.UdpPoolUtil;
import com.sojson.udp.util.UdpUtil;
import com.sojson.udp.util.bean.UdpConnect;
import com.sojson.udp.util.enums.EUdpControl;
import com.sojson.util.HexUtil;
import com.sojson.util.encrypt.bothway.alike.aes.AesUtil;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.socket.DatagramPacket;
import io.netty.util.AttributeKey;
import lombok.extern.slf4j.Slf4j;

/**
 * Udp处理器
 * 
 * @author liu
 * @date 2024-06-04
 */
@Slf4j
@Component
public class UdpHandler extends SimpleChannelInboundHandler<DatagramPacket> {

    @Autowired
    private UdpHandlerHeartbeat heartbeat;
    @Autowired
    private UdpHandlerControl control;
    /** 使用 CompletableFuture 用于异步获取客户端的响应 */
    public static CompletableFuture<String> responseFuture = new CompletableFuture<>();

    /**
     * 建立连接时触发的方法
     * 
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        super.channelActive(ctx);
    }

    /**
     * 关闭连接时触发的方法
     * 
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        Object object = ctx.channel().attr(AttributeKey.valueOf(UdpPoolUtil.ADDR_KEY)).get();
        String addr = null;
        if (object != null) {
            addr = object.toString();
            // 从连接池中删除
            UdpPoolUtil.remove(addr);
        }
        super.channelInactive(ctx);
    }

    /**
     * 发生错误时触发的方法
     * 
     * @param ctx
     * @param e
     * @throws Exception
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable e) throws Exception {
        Object object = ctx.channel().attr(AttributeKey.valueOf(UdpPoolUtil.ADDR_KEY)).get();
        String addr = null;
        if (object != null) {
            addr = object.toString();
            // 从连接池中删除
            UdpPoolUtil.remove(addr);
        }
        super.exceptionCaught(ctx, e);
        log.error(new StringBuilder("Udp连接发生错误: ").append(addr).append(",").append(e.getMessage()).toString());
        log.error(e.getMessage(), e);
    }

    /**
     * 收到消息后执行的方法
     * 
     * @param ctx
     * @param msg
     * @throws Exception
     */
    @Override
    public void channelRead0(ChannelHandlerContext ctx, DatagramPacket packet) throws Exception {
        String data = null;
        String addr = null;
        String addrRever = null;
        // 解析数据
        byte[] barr;
        int len = packet.content().readableBytes();
        if (packet.content().hasArray()) {
            barr = packet.content().array();
        } else {
            barr = new byte[len];
            packet.content().getBytes(packet.content().readerIndex(), barr);
        }
        data = HexUtil.bytesToHexString(barr).trim();
        addr = data.substring(6, 20);
        addrRever = HexUtil.reverse(addr);

        UdpConnect connect = new UdpConnect();
        connect.setCtx(ctx);
        connect.setPacket(packet);
        UdpPoolUtil.put(addrRever, connect);
        log.info(new StringBuilder("Udp收到来自: ").append(addrRever).append("的消息,").append(data).toString());

        if (!data.startsWith(UdpUtil.HEAD)) {
            log.info("Udp收到其他包,此功能未实现: " + addrRever);
        }

        len = data.length() / 2;
        // 功能码
        String funcCode = data.substring(28, 32);
        // 数据域字节数
        String dataByteNum = data.substring(32, 36);
        // 数据(解密前)
        String datas = data.substring(36, (len - 2) * 2);
        // 数据(解密后)
        String datasDecode = AesUtil.decryptByHex(datas, UdpUtil.key);
        // 校验码
        String verifyCode = data.substring((len - 2) * 2, (len - 1) * 2);

        HexUtil.dataLenVerify(datas, HexUtil.reverse(dataByteNum));
        HexUtil.dataVerify(data, verifyCode, UdpUtil.HEAD, (len - 2) * 2);

        // 分类处理
        if (EUdpControl.HEARTBEAT.getCode().equals(funcCode)) {
            // 心跳包
            log.info("Udp收到心跳包: " + addrRever);
            heartbeat.run(ctx, datasDecode, addr, addrRever);
        } else if (EUdpControl.CONTROL_VALUE.getCode().equals(funcCode)) {
            // 控阀包
            log.info("Udp收到控阀包: " + addrRever);
            control.run(ctx, datasDecode, addrRever);
        } else {
            log.info("Udp收到其他包,此功能未实现: " + addrRever);
        }
    }

}
